package com.lill.system.config;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;

import com.lill.org.service.ICompanyBranchService;
import com.lill.system.constant.SystemConstant;
import com.lill.system.dao.ISysDomainDao;
import com.lill.system.dao.ISysMenuDao;
import com.lill.system.dao.ISysUserDao;
import com.lill.system.model.SysDomainCompanyModel;
import com.lill.system.model.SysMenuEntity;
import com.lill.system.model.SysUserEntity;

/**
 * 认证
 *
 * @author lill
 */
public class UserShiroRealm extends AuthorizingRealm {
	
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
    @Autowired(required=false)
    private ISysUserDao sysUserDao;
    @Autowired(required=false)
    private ISysDomainDao domainDao;
    @Autowired(required=false)
    private ISysMenuDao sysMenuDao;
    @Lazy
    @Autowired(required=false)
    private ICompanyBranchService branchService;
    @Resource(name="commonRedisTemplate")
    private RedisTemplate<String, List<String>> redisTemplate;
    
    /**
     * 授权(验证权限时调用)
     */
	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Object userObj=principals.getPrimaryPrincipal();
		String permsKey=SystemConstant.SYS_PERMS_KEY;
		try {
			permsKey+=new PropertyDescriptor("id", userObj.getClass()).getReadMethod().invoke(userObj).toString();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		
		String sessionId=SecurityUtils.getSubject().getSession().getId().toString();
        List<String> permsValues=redisTemplate.opsForValue().get(permsKey);
        redisTemplate.expire(permsKey, SystemConstant.SYS_CACHE_SESSION_TIME,TimeUnit.SECONDS);
        redisTemplate.expire(CluterShiroSessionDao.SESSION_KEY+sessionId, SystemConstant.SYS_CACHE_SESSION_TIME,TimeUnit.SECONDS);
        //用户权限列表
        Set<String> permsSet = new HashSet<String>();
        if (permsValues != null && permsValues.size() != 0) {
            for (String perms : permsValues) {
                if (StringUtils.isBlank(perms)) {
                    continue;
                }
                permsSet.addAll(Arrays.asList(perms.trim().split(",")));
            }
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        SysUserEntity user = sysUserDao.queryByUserName(username);;
        //账号不存在
        if (user == null) {
            throw new UnknownAccountException("账号或密码不正确,用户不存在");
        }

        //密码错误
        if (!password.equals(user.getPassWord())) {
            throw new IncorrectCredentialsException("账号或密码不正确");
        }

        //账号锁定
        if (user.getStatus() == 0) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }

        // 把当前用户放入到session中
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession(true);
        session.setAttribute(SystemConstant.CURRENT_USER, user);

        if (SystemConstant.SUPER_ADMIN.equals(user.getId())) {
        	user.setCompanyId(SystemConstant.DEFAULT_COMPANY_ID);
        	user.setCompanyName(SystemConstant.SYS_COMPANY);
        }else{
        	Map<String, Object> params=new HashMap<String, Object>();
        	params.put("userId", user.getId());
        	List<SysDomainCompanyModel> domainCompanyList=domainDao.queryUserAll(params);
        	if(null!=domainCompanyList&&!domainCompanyList.isEmpty()){
        		user.setCompanyId(domainCompanyList.get(0).getCompanyId());
				user.setCompanyName(domainCompanyList.get(0).getCompanyName());
				user.setCompanyCode(domainCompanyList.get(0).getCompanyCode());
				user.setDepartId(domainCompanyList.get(0).getDepartId());
				user.setDepartName(domainCompanyList.get(0).getDepartName());
				user.setDomainId(domainCompanyList.get(0).getId());
				user.setDomainName(domainCompanyList.get(0).getDomainName());
				user.setPosition(domainCompanyList.get(0).getPosition());
				user.setEmployeeId(domainCompanyList.get(0).getEmployeeId());
				if(null!=domainCompanyList.get(0).getCompanyType()&&1==domainCompanyList.get(0).getCompanyType()){
					if(StringUtils.isNotEmpty(domainCompanyList.get(0).getDepartId())&&branchService!=null){
						Map<String, Object> branchInfo=branchService.queryUserFirstBranch(domainCompanyList.get(0).getDepartId());
						if(null!=branchInfo&&!branchInfo.isEmpty()){
							user.setBranchId(branchInfo.get("branch_id")+"");
							user.setBranchName(branchInfo.get("branch_name")+"");
							user.setBranchCode(branchInfo.get("branch_code")+"");
						}
					}
				}else{
					user.setBranchId(domainCompanyList.get(0).getCompanyId());
					user.setBranchName(domainCompanyList.get(0).getCompanyName());
					user.setBranchCode(domainCompanyList.get(0).getCompanyCode());
				}
        	}else{
        		throw new UnknownAccountException("账号有误，请和所在公司核实！");
        	}
        }

        List<String> permsList=null;
        //系统管理员，拥有最高权限
        if (SystemConstant.SUPER_ADMIN.equals(user.getId())) {
            List<SysMenuEntity> menuList = sysMenuDao.queryList(new HashMap<String, Object>());
            permsList = new ArrayList<String>(menuList.size());
            for (SysMenuEntity menu : menuList) {
                permsList.add(menu.getPerms());
            }
        } else {
            permsList = sysUserDao.queryAllPerms(user.getId());
        }

        if (SystemConstant.SUPER_ADMIN.equals(user.getId())) {
            Map<String, Object> adminParam=new HashMap<String, Object>();
            adminParam.put("domainId", user.getDomainId());
            List<SysMenuEntity> menuList = sysMenuDao.queryList(adminParam);
            permsList = new ArrayList<String>();
            for (SysMenuEntity menu : menuList) {
                permsList.add(menu.getPerms());
                if(StringUtils.isNotEmpty(menu.getPerms())){
                    String[] perms=menu.getPerms().split(",");
                    for (String permVal : perms) {
                        permsList.add(permVal);
                    }
                }
            }
        } else {
            Map<String, Object> userParam=new HashMap<String, Object>();
            userParam.put("userId", user.getId());
            userParam.put("companyId", user.getCompanyId());
            userParam.put("domainId", user.getDomainId());
            List<SysMenuEntity> menuList=sysMenuDao.queryCurUserMenuList(userParam);
            permsList = new ArrayList<String>();
            if(null!=menuList&&!menuList.isEmpty()){
                for (SysMenuEntity menu : menuList) {
                    if(StringUtils.isNotEmpty(menu.getPerms())){
                        String[] perms=menu.getPerms().split(",");
                        for (String permVal : perms) {
                            permsList.add(permVal);
                        }
                    }
                }
            }
        }
        
        redisTemplate.opsForValue().set(SystemConstant.SYS_PERMS_KEY+user.getId(), permsList, SystemConstant.SYS_CACHE_SESSION_TIME, TimeUnit.SECONDS);


        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }

}
